#include <stdio.h>
#include <stdlib.h>
#include "lineedit.h"
#ifdef _WIN32
#include <WinSock2.h>
#include <Windows.h>
#include <Ws2tcpip.h>
#else
#include <string.h>
#include <sys/socket.h>       /*  socket definitions        */
#include <sys/types.h>        /*  socket types              */
#include <arpa/inet.h>        /*  inet (3) funtions         */
#include <unistd.h>           /*  misc. UNIX functions      */
#include <errno.h>

#endif



void completion(DESC* fd, const char *buf, lineeditCompletions *lc) {
    if (buf[0] == 'h') {
        lineeditAddCompletion(fd, lc,"hello");
        lineeditAddCompletion(fd, lc,"hello there");
    }
}
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "23"

#ifdef _WIN32
int winSockRead(void* userContext, DESC* fd, char* buff, size_t size)
{
    return recv((SOCKET)userContext, buff, size, 0);

}

int winSockWrite(void* userContext, DESC* fd, const char* buff, size_t size)
{
    return send((SOCKET)userContext, buff, size, 0);

}
int socketTest()
{
	WSADATA wsaData;
	int iResult;

	SOCKET ListenSocket = INVALID_SOCKET;
	SOCKET ClientSocket = INVALID_SOCKET;

	struct addrinfo *result = NULL;
	struct addrinfo hints;

	int recvbuflen = DEFAULT_BUFLEN;

	// Initialize Winsock
	iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
	if (iResult != 0) {
		printf("WSAStartup failed with error: %d\n", iResult);
		return 1;
	}

	ZeroMemory(&hints, sizeof(hints));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = AI_PASSIVE;

	// Resolve the server address and port
	iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
	if ( iResult != 0 ) {
		printf("getaddrinfo failed with error: %d\n", iResult);
		WSACleanup();
		return 1;
	}

	// Create a SOCKET for connecting to server
	ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
	if (ListenSocket == INVALID_SOCKET) {
		printf("socket failed with error: %ld\n", WSAGetLastError());
		freeaddrinfo(result);
		WSACleanup();
		return 1;
	}

	// Setup the TCP listening socket
	iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
	if (iResult == SOCKET_ERROR) {
		printf("bind failed with error: %d\n", WSAGetLastError());
		freeaddrinfo(result);
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}

	freeaddrinfo(result);

	iResult = listen(ListenSocket, SOMAXCONN);
	if (iResult == SOCKET_ERROR) {
		printf("listen failed with error: %d\n", WSAGetLastError());
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}

	// Accept a client socket
	ClientSocket = accept(ListenSocket, NULL, NULL);
	if (ClientSocket == INVALID_SOCKET) {
		printf("accept failed with error: %d\n", WSAGetLastError());
		closesocket(ListenSocket);
		WSACleanup();
		return 1;
	}

	// No longer need server socket
	closesocket(ListenSocket);

	{
		char *line;
        lineeditConfig config;
        DESC* fd;
        config.termType     = lineedit_USER;
        config.lineeditRead  = winSockRead;
        config.lineeditWrite = winSockWrite;
        config.userContext  = (void*)ClientSocket;

		fd = lineeditInit(&config);

		lineeditSetCompletionCallback(fd, completion);
		lineeditHistoryLoad(fd, "history.txt"); /* Load the history at startup */
		//while((line = lineedit(fd, "hello> ")) != NULL) {
        while(1) {
            line = lineedit(fd, "hello> ");
            if (line != NULL ) {
			    if (line[0] != '\0') {
				    char buf[1024];
				    size_t len;
				    len = _snprintf(buf, 1024,"echo: '%s'\n", line );
				    send(ClientSocket,buf, len,0);
				    lineeditHistoryAdd(fd, line);
				    lineeditHistorySave(fd, "history.txt"); /* Save every new entry */
			    }
            free(line);
            }
			
		}
	}


	return 0;

}
#else
int linSockRead(void* userContext, DESC* fd, char* buff, size_t size)
{
    return read((int)userContext, buff, size);

}

int linSockWrite(void* userContext, DESC* fd, const char* buff, size_t size)
{
    return write((int)userContext, buff, size);

}

int socketTest()
{
    int       list_s;                /*  listening socket          */
    int       conn_s;                /*  connection socket         */
    short int port=4567;                  /*  port number               */
    struct    sockaddr_in servaddr;  /*  socket address structure  */

 /*  Create the listening socket  */

    if ( (list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
	fprintf(stderr, "lineedit: Error creating listening socket.\n");
	exit(EXIT_FAILURE);
    }


    /*  Set all bytes in socket address structure to
        zero, and fill in the relevant data members   */

    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(port);


    /*  Bind our socket addresss to the 
	listening socket, and call listen()  */

    if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
	fprintf(stderr, "lineedit: Error calling bind()\n");
	exit(EXIT_FAILURE);
    }

    if ( listen(list_s, 1) < 0 ) {
	fprintf(stderr, "lineedit: Error calling listen()\n");
	exit(EXIT_FAILURE);
    }

    
    /*  Enter an infinite loop to respond
        to client requests and echo input  */


	/*  Wait for a connection, then accept() it  */

	if ( (conn_s = accept(list_s, NULL, NULL) ) < 0 ) {
	    fprintf(stderr, "ECHOSERV: Error calling accept()\n");
	    exit(EXIT_FAILURE);
	}


	{
		char *line;
        lineeditConfig config;
        DESC* fd;
        config.termType     = lineedit_USER;
        config.lineeditRead  = linSockRead;
        config.lineeditWrite = linSockWrite;
        config.userContext  = (void*)conn_s;

	fd = lineeditInit(&config);

	lineeditSetCompletionCallback(fd, completion);
	lineeditHistoryLoad(fd, "history.txt"); /* Load the history at startup */
	//while((line = lineedit(fd, "hello> ")) != NULL) {
        while(1) {
            line = lineedit(fd, "hello> ");
            if (line != NULL ) {
			    if (line[0] != '\0') {
				    char buf[1024];
				    size_t len;
				    len = snprintf(buf, 1024,"echo: '%s'\n", line );
				    write(conn_s,buf, len);
				    lineeditHistoryAdd(fd, line);
				    lineeditHistorySave(fd, "history.txt"); /* Save every new entry */
			    }
            free(line);
            }
			
		}
	}
}
#endif

int main(void) {
    char *line;

	return socketTest();
	{
 
		DESC* fd = lineeditInit(NULL);
		lineeditSetCompletionCallback(fd, completion);
		lineeditHistoryLoad(fd, "history.txt"); /* Load the history at startup */
		while((line = lineedit(fd, "hello> ")) != NULL) {
			if (line[0] != '\0') {
				printf("echo: '%s'\n", line);
				lineeditHistoryAdd(fd, line);
				lineeditHistorySave(fd, "history.txt"); /* Save every new entry */
			}
			free(line);
		}
		return 0;
	}
	}

